/***************************************************************************
 *   Copyright (C) 2007, 2008 by Andreas Theofilu                          *
 *   andreas@theosys.at                                                    *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation version 3 of the License.                *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

#include <time.h>
#include <string.h>
#include <math.h>
#include "garmin.h"
#include "disassemble.h"

#define Deg2Rad(n)	((n) * DEG_2_RAD)

disassemble::disassemble()
{
	lap_node = 0;
	run_node = 0;
	point_node = 0;

	totalDistance = 0.0;
	totalTime = 0;
	avgHR = 0.0;
	avgSpeed = 0.0;
	maxSpeed = 0.0;
	ascend = 0.0;
	descend = 0.0;
}

disassemble::~disassemble()
{
	destroy();
}

void disassemble::destroy()
{
LAP_NODE *lakt, *ln;
RUN_NODE *rakt, *rn;
POINT_NODE *pakt, *pn;

	if (lap_node != NULL)		// free allocated laps
	{
	   lakt = lap_node;

	   while (lakt)
	   {
	      ln = lakt;
	      delete ln->lap;
	      lakt = lakt->next;
	      delete ln;
	   }
	}

	lap_node = NULL;

	if (lap_node != NULL)		// free allocated runs
	{
	   rakt = run_node;

	   while (rakt)
	   {
	      rn = rakt;
	      delete rn->run;
	      rakt = rakt->next;
	      delete rn;
	   }
	}

	run_node = NULL;

	if (point_node != NULL)		// free allocated points
	{
	   pakt = point_node;

	   while (pakt)
	   {
	      pn = pakt;
	      delete pn->point;
	      pakt = pakt->next;
	      delete pn;
	   }
	}

	point_node = NULL;

	totalDistance = 0.0;
	totalTime = 0;
	avgHR = 0.0;
	avgSpeed = 0.0;
	maxSpeed = 0.0;
	ascend = 0.0;
	descend = 0.0;

}

LAP_NODE *disassemble::addLap ()
{
LAP_NODE *akt, *n;

	if (lap_node == 0)		// First lap to add
	{
	   lap_node = new LAP_NODE;
	   lap_node->lap = new LAP;

	   memmove (lap_node->lap, &lap, sizeof(LAP));
	   lap_node->next = 0;
	   akt = lap_node;
	}
	else				// additional lap to add
	{
	   n = lap_node;

	   while (n->next)
	      n = n->next;

	   akt = new LAP_NODE;
	   akt->lap = new LAP;
	   memmove (akt->lap, &lap, sizeof(LAP));
	   akt->next = 0;
	   n->next = akt;
	}

	return akt;
}

LAP *disassemble::getLap(int index)
{
LAP_NODE *akt = lap_node;

	while (akt)
	{
	   if (akt->lap->index == (uint32)index)
	      return akt->lap;

	   akt = akt->next;
	}

	return NULL;
}

LAP *disassemble::getLapT(uint32 time)
{
LAP_NODE *akt = lap_node;

	while (akt)
	{
	   if ((akt->lap->start_time + akt->lap->total_time / 100) >= time)
	      return akt->lap;

	   akt = akt->next;
	}

	return NULL;
}

RUN_NODE *disassemble::addRun ()
{
RUN_NODE *akt, *n;

	if (run_node == 0)		// First run to add
	{
	   run_node = new RUN_NODE;
	   run_node->run = new RUN;

	   memmove (run_node->run, &run, sizeof(RUN));
	   run_node->next = 0;
	   akt = run_node;
	}
	else				// additional run to add
	{
	   n = run_node;

	   while (n != NULL && n->next != NULL)
	      n = n->next;

	   akt = new RUN_NODE;
	   akt->run = new RUN;
	   memmove (akt->run, &run, sizeof(RUN));
	   akt->next = 0;
	   n->next = akt;
	}

	return akt;
}

POINT_NODE *disassemble::addPoint ()
{
POINT_NODE *akt, *n;

	if (point_node == 0)		// First point to add
	{
	   point_node = new POINT_NODE;
	   point_node->point = new POINT;

	   memmove (point_node->point, &point, sizeof(POINT));
	   point_node->number = 0;
	   point_node->next = 0;
	   akt = point_node;
	}
	else				// additional point to add
	{
	   n = point_node;

	   while (n != NULL && n->next != NULL)
	      n = n->next;

	   akt = new POINT_NODE;
	   akt->point = new POINT;
	   memmove (akt->point, &point, sizeof(point));
	   akt->number = n->number + 1;
	   akt->next = 0;
	   n->next = akt;
	}

	return akt;
}

POINT *disassemble::getPoint(int number)
{
POINT_NODE *akt;

	akt = point_node;

	while (akt)
	{
	   if (akt->number == number)
	      return akt->point;

	   akt = akt->next;
	}

	return 0;
}

POINT *disassemble::getPoint(uint32 time)
{
POINT_NODE *akt;

	akt = point_node;

	while (akt)
	{
	   if (akt->point->time >= time)
	      return akt->point;

	   akt = akt->next;
	}

	return 0;
}

/* 
   This file contains functions to get Garmin datatypes.
   The functions aim to reproduce the data losslessly, including
   floating point data, such that the data can be scanned back from the
   output and reconstructed exactly.
*/

void disassemble::garmin_print_dlist (garmin_list *l)
{
garmin_list_node *n;
POINT_NODE *akt;
uint32 time = 0;
int countHR = 0;
int countCD = 0;
bool pause = false;
bool edTime = false;
uint32 stTime, pTime;
int arrDist[20];
uint32 arrTime[20];
float32 oldAlt, arrAlt[20];
int distPos;

	for (n = l->head; n != NULL; n = n->next)
	{
	   garmin_print_data(n->data);
	}

	// Here all data is into the struct and now we
	// figure out some statistics
	akt = point_node;
	pTime = 0;
	distPos = 0;
	oldAlt = 0;
	descend = 99999;

	if (akt && akt->point)
	   time = akt->point->time;	// Save the time code of the first point
	else
	   time = 0;

	while (akt)
	{
	   // Find out the pause and detect how much seconds it is.
	   if (!pause && akt->point->distance >= 0x7fffffff)
	   {
	      pause = true;
	      stTime = akt->point->time;
	      akt = akt->next;
	      continue;
	   }

	   if (pause && akt->point->distance >= 0x7fffffff)
	   {
	      pause = false;
	      edTime = true;
	      akt = akt->next;
	      continue;
	   }

	   if (pause && akt->point->distance < 0x7fffffff)
	   {
	      pause = false;
	      edTime = true;
	   }

	   if (edTime)
	   {
	      pTime += (akt->point->time - stTime);
	      edTime = false;
	   }

	   // If we have a normal point, use it!
	   if (akt->point->distance < 0x7fffffff)
	   {
	      totalDistance = akt->point->distance;
	      arrDist[distPos] = akt->point->distance;
	      arrTime[distPos] = akt->point->time;
	      arrAlt[distPos] = akt->point->alt;
	      distPos++;

	      if (distPos > 19)
	      {
	      double speed, alt, sumDist = 0.0;
	      int secs = arrTime[19] - arrTime[0];

		 for (int i = 0; i < 19; i++)
		    sumDist += arrDist[i];

		 speed = sumDist / secs * 3.6;

		 if (speed > maxSpeed)
		    maxSpeed = speed;

		 alt = 0.0;

		 for (int i = 0; i < 19; i++)
		    alt += arrAlt[i];

		 alt /= 20.0;

		 if (oldAlt < alt)
		 {
		    ascend += (alt - oldAlt);
		    oldAlt = alt;
		 }

		 if (descend > alt)
		    descend = akt->point->alt;

		 distPos = 0;
	      }

	      if (akt->point->heart_rate > 0x00 && akt->point->heart_rate < 0xff)
	      {
		 avgHR += akt->point->heart_rate;
		 countHR++;
	      }

	      if (akt->point->cadence > 0 && akt->point->cadence != 0xff)
	      {
		 avgCadence += akt->point->cadence;
		 countCD++;
	      }
	   }

	   totalTime = akt->point->time;
	   akt = akt->next;
	}

	if (countHR > 0)
	   avgHR /= countHR;

	if (countCD > 0)
	   avgCadence /= countCD;

	if (point_node)
	{
	   totalTime -= time;		// We need the number of seconds
	   totalTime -= pTime;		// Subtract the seconds of pause
	}
	else
	   totalTime = 0;

	if (totalTime > 0)
	   avgSpeed = (totalDistance / 100.0) / totalTime * 3.6;

	pauseTime = pTime;
}

POINT *disassemble::getLastPoint()
{
POINT_NODE *old, *akt = point_node;

	if (!akt)
	   return 0;

	old = 0;

	while (akt)
	{
	   old = akt;

	   if (!akt->next && akt->point)
	   {
	      if (akt->point->distance >= 0x7fffffff && old)
		 return old->point;

	      return akt->point;
	   }

	   akt = akt->next;
	}

	return 0;	// This should never happen!
}

/* Support function to print a time value in ISO 8601 compliant format */

char *disassemble::garmin_print_dtime (uint32 t)
{
time_t     tval;
struct tm  tmval;
char       buf[128], hv0[128];
int        len;

	/* 
	                                012345678901234567890123
	   This will make, for example, 2007-04-20T23:55:01-0700, but that date
	   isn't quite ISO 8601 compliant.  We need to stick a ':' in the time
	   zone between the hours and the minutes.
	*/

	tval = t + TIME_OFFSET;
	localtime_r(&tval,&tmval);
	strftime(buf,sizeof(buf)-1,"%FT%T%z",&tmval);

	/* 
	   If the last character is a 'Z', don't do anything.  Otherwise, we 
	   need to move the last two characters out one and stick a colon in 
	   the vacated spot.  Let's not forget the trailing '\0' that needs to 
	   be moved as well.
	*/

	len = strlen(buf);

	if ( len > 0 && buf[len-1] != 'Z' )
	{
	   memmove(buf+len-1,buf+len-2,3);
	   buf[len-2] = ':';
	}

	/* OK.  Done. */

	sprintf(hv0,"%s", buf);
	return (char *)strdup(hv0);
}


/* Support function to print a position type */

void disassemble::garmin_print_dpos (position_type *pos, double *lat, double *lon)
{
	if ( pos->lat != 0x7fffffff )
	   *lat = SEMI2DEG(pos->lat);

	if ( pos->lon != 0x7fffffff )
	   *lon = SEMI2DEG(pos->lon);
}


/* 
   Print a float32 with enough precision such that it can be reconstructed
   exactly from its decimal representation.
*/

char *disassemble::garmin_print_float32 (float32 f, char *ret)
{
	if (!ret)
	   return NULL;

	if ( f > 100000000.0 || f < -100000000.0 )
	    sprintf(ret, "%.9e",f);
	else if ( f > 10000000.0 || f < -10000000.0 )
	   sprintf(ret, "%.1f",f);
	else if ( f > 1000000.0 || f < -1000000.0 )
	   sprintf(ret, "%.2f",f);
	else if ( f > 100000.0 || f < -100000.0 )
	   sprintf(ret, "%.3f",f);
	else if ( f > 10000.0 || f < -10000.0 )
	   sprintf(ret, "%.4f",f);
	else if ( f > 1000.0 || f < -1000.0 )
	   sprintf(ret, "%.5f",f);
	else if ( f > 100.0 || f < -100.0 )
	   sprintf(ret, "%.6f",f);
	else if ( f > 10.0 || f < -10.0 )
	   sprintf(ret, "%.7f",f);
	else if ( f > 1.0 || f < -1.0 )
	   sprintf(ret, "%.8f",f);
	else if ( f > 0.1 || f < -0.1 )
	   sprintf(ret, "%.9f",f);
	else if ( f != 0 )
	   sprintf(ret, "%.9e",f);
	else
	   sprintf(ret, "%.8f",f);

	return ret;
}


/* 
   Print a float64 with enough precision such that it can be reconstructed
   exactly from its decimal representation.
*/

char *disassemble::garmin_print_float64 (float64 f, char *ret)
{
	if ( f > 10000000000000000.0 || f < -10000000000000000.0 )
	   sprintf(ret,"%.17e",f);
	else if ( f > 1000000000000000.0 || f < -1000000000000000.0 )
	   sprintf(ret,"%.1f",f);
	else if ( f > 100000000000000.0 || f < -100000000000000.0 )
	   sprintf(ret,"%.2f",f);
	else if ( f > 10000000000000.0 || f < -10000000000000.0 )
	   sprintf(ret,"%.3f",f);
	else if ( f > 1000000000000.0 || f < -1000000000000.0 )
	   sprintf(ret,"%.4f",f);
	else if ( f > 100000000000.0 || f < -100000000000.0 )
	   sprintf(ret,"%.5f",f);
	else if ( f > 10000000000.0 || f < -10000000000.0 )
	   sprintf(ret,"%.6f",f);
	else if ( f > 1000000000.0 || f < -1000000000.0 )
	   sprintf(ret,"%.7f",f);
	else if ( f > 100000000.0 || f < -100000000.0 )
	   sprintf(ret,"%.8f",f);
	else if ( f > 10000000.0 || f < -10000000.0 )
	   sprintf(ret,"%.9f",f);
	else if ( f > 1000000.0 || f < -1000000.0 )
	   sprintf(ret,"%.10f",f);
	else if ( f > 100000.0 || f < -100000.0 )
	   sprintf(ret,"%.11f",f);
	else if ( f > 10000.0 || f < -10000.0 )
	   sprintf(ret,"%.12f",f);
	else if ( f > 1000.0 || f < -1000.0 )
	   sprintf(ret,"%.13f",f);
	else if ( f > 100.0 || f < -100.0 )
	   sprintf(ret,"%.14f",f);
	else if ( f > 10.0 || f < -10.0 )
	   sprintf(ret,"%.15f",f);
	else if ( f > 1.0 || f < -1.0 )
	   sprintf(ret,"%.16f",f);
	else if ( f > 0.1 || f < -0.1 )
	   sprintf(ret,"%.17f",f);
	else if ( f != 0 )
	   sprintf(ret,"%.17e",f);
	else
	   sprintf(ret,"%.16f",f);

	return ret;
}


/* 
   Print a float32 whose value is invalid (and should not be printed) if 
   greater than 1.0e24 
*/

char *disassemble::garmin_print_dfloat32 (float32 f, char *ret)
{
	if (!ret)
	   return NULL;

	if ( f < 1.0e24 )
	   garmin_print_float32(f, ret);

	return ret;
}


/* Print a duration and distance. */

char *disassemble::garmin_print_ddist (uint32 dur, char *ret)
{
int  hun;
int  sec;
int  min;
int  hrs;

	if (!ret)
	   return NULL;

	hun  = dur % 100;
	dur -= hun;
	dur /= 100;
	sec  = dur % 60;
	dur -= sec;
	dur /= 60;
	min  = dur % 60;
	dur -= min;
	dur /= 60;
	hrs  = dur;

	sprintf(ret,"%d:%02d:%02d.%02d", hrs, min, sec, hun);
	return ret;
}


/* --------------------------------------------------------------------------*/
/* 7.4.1  D100                                                               */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d100 (D100 *x)
{
	memset (&waypoint, 0, sizeof(WAYPOINT));
	waypoint.type = 100;
	strncpy (waypoint.ident, x->ident, 5);
	waypoint.posn = x->posn;
	strncpy(waypoint.cmnt, x->cmnt, 40);
}


/* --------------------------------------------------------------------------*/
/* 7.4.2  D101                                                               */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d101 (D101 *x)
{
	memset (&waypoint, 0, sizeof(WAYPOINT));
	waypoint.type = 101;
	strncpy (waypoint.ident, x->ident, sizeof(waypoint.ident)-1);
	waypoint.posn = x->posn;
	strncpy (waypoint.cmnt, x->cmnt, sizeof(waypoint.cmnt)-1);
	waypoint.dst = x->dst;
	waypoint.smbl = x->smbl;
}


/* --------------------------------------------------------------------------*/
/* 7.4.3  D102                                                               */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d102 (D102 *x)
{
	garmin_print_d101 ((D101 *)x);
	waypoint.type = 102;
}


/* --------------------------------------------------------------------------*/
/* 7.4.4  D103                                                               */
/* --------------------------------------------------------------------------*/


void disassemble::garmin_print_d103 (D103 *x)
{
	garmin_print_d101((D101 *)x);
	waypoint.type = 103;
//	GARMIN_TAGSTR(1,"symbol",garmin_d103_smbl(x->smbl));
//	GARMIN_TAGSTR(1,"display",garmin_d103_dspl(x->dspl));
}


/* --------------------------------------------------------------------------*/
/* 7.4.5  D104                                                               */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d104 (D104 *x)
{
	garmin_print_d101((D101 *)x);
	waypoint.dspl = x->dspl;
	waypoint.type = 104;
//	GARMIN_TAGF32(1,"proximity_distance",x->dst);
//	GARMIN_TAGSTR(1,"display",garmin_d104_dspl(x->dspl));
}


/* --------------------------------------------------------------------------*/
/* 7.4.6  D105                                                               */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d105 (D105 *x)
{
	memset (&waypoint, 0, sizeof(WAYPOINT));
	waypoint.type = 105;
	waypoint.wpt_ident = x->wpt_ident;
	waypoint.posn = x->posn;
	waypoint.smbl = x->smbl;
}


/* --------------------------------------------------------------------------*/
/* 7.4.7  D106                                                               */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d106 (D106 *x)
{
	memset (&waypoint, 0, sizeof(WAYPOINT));
	waypoint.type = 106;
	waypoint.wpt_class = x->wpt_class;
	waypoint.subclass[0] = 0;

	if ( x->wpt_class != 0 )
	{
	   strncpy ((char *)waypoint.subclass, (char *)x->subclass, 13);
	   waypoint.subclass[13] = 0;
	}

	waypoint.wpt_ident = x->wpt_ident;
	waypoint.posn = x->posn;
	waypoint.smbl = x->smbl;
	waypoint.lnk_ident = x->lnk_ident;
}


/* --------------------------------------------------------------------------*/
/* 7.4.8  D107                                                               */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d107 (D107 *x)
{
	memset (&waypoint, 0, sizeof(WAYPOINT));
	waypoint.type = 107;
	strncpy(waypoint.ident, x->ident, sizeof(waypoint.ident)-1);
	waypoint.posn = x->posn;
	strncpy(waypoint.cmnt, x->cmnt, sizeof(waypoint.cmnt)-1);
	waypoint.dst = x->dst;
	waypoint.smbl = x->smbl;
	waypoint.dspl = x->dspl;
	waypoint.color = x->color;
}


/* --------------------------------------------------------------------------*/
/* 7.4.9  D108                                                               */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d108 (D108 *x)
{
	memset(&waypoint, 0, sizeof(WAYPOINT));
	waypoint.type = 108;
	waypoint.identity = x->ident;
	waypoint.posn = x->posn;
	waypoint.comment = x->comment;
	waypoint.smbl = x->smbl;
	waypoint.dspl = x->dspl;
	waypoint.wpt_class = x->wpt_class;
	strncpy((char *)waypoint.subclass, (char *)x->subclass, 18);
	waypoint.attr = x->attr;
	waypoint.color = x->color;
	waypoint.alt = x->alt;
	waypoint.dpth = x->dpth;
	waypoint.dst = x->dist;
	waypoint.facility = x->facility;
	waypoint.city = x->city;
	waypoint.addr = x->addr;
	waypoint.cross_road = x->cross_road;
}


/* --------------------------------------------------------------------------*/
/* 7.4.10  D109                                                              */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d109 (D109 *x)
{
uint8 color = x->dspl_color & 0x1f;

	if (color == 0x1f)
	   color = D108_default_color;

	memset(&waypoint, 0, sizeof(WAYPOINT));
	waypoint.type = 109;
	waypoint.identity = x->ident;
	waypoint.posn = x->posn;
	waypoint.comment = x->comment;
	waypoint.smbl = x->smbl;
	waypoint.wpt_class = x->wpt_class;
	strncpy((char *)waypoint.subclass, (char *)x->subclass, 18);
	waypoint.attr = x->attr;
	waypoint.color = color;
	waypoint.alt = x->alt;
	waypoint.dtyp = x->dtyp;
	waypoint.ete = x->ete;
	waypoint.dpth = x->dpth;
	waypoint.dst = x->dist;
	waypoint.facility = x->facility;
	waypoint.city = x->city;
	waypoint.addr = x->addr;
	waypoint.cross_road = x->cross_road;
}


/* --------------------------------------------------------------------------*/
/* 7.4.11  D110                                                              */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d110 (D110 *x)
{
	memset(&waypoint, 0, sizeof(WAYPOINT));
	waypoint.type = 110;
	waypoint.identity = x->ident;
	waypoint.posn = x->posn;
	waypoint.comment = x->comment;
	waypoint.smbl = x->smbl;
	waypoint.wpt_class = x->wpt_class;
	strncpy((char *)waypoint.subclass, (char *)x->subclass, 18);
	waypoint.attr = x->attr;
	waypoint.alt = x->alt;
	waypoint.dtyp = x->dtyp;
	waypoint.ete = x->ete;
	waypoint.dpth = x->dpth;
	waypoint.dst = x->dist;
	waypoint.facility = x->facility;
	waypoint.city = x->city;
	waypoint.addr = x->addr;
	waypoint.cross_road = x->cross_road;

/*  GARMIN_TAGSTR(1,"wpt_class",garmin_d110_wpt_class(x->wpt_class));
  GARMIN_TAGSTR(1,"color",garmin_d110_color((x->dspl_color) & 0x1f));
  GARMIN_TAGSTR(1,"display",garmin_d110_dspl((x->dspl_color >> 5) & 0x03));
  GARMIN_TAGSYM(1,"symbol",x->smbl);
  if ( x->temp < 1.0e24 ) GARMIN_TAGF32(1,"temperature",x->temp);
  GARMIN_TAGSTR(1,"state",x->state);
  GARMIN_TAGSTR(1,"country_code",x->cc);
  if ( x->time != 0xffffffff ) GARMIN_TAGU32(1,"time",x->time);
  GARMIN_TAGHEX(1,"category",x->wpt_cat); */
}


/* --------------------------------------------------------------------------*/
/* 7.4.12  D120                                                              */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d120 (D120 *x)
{
	memset(&wpcategory, 0, sizeof(WPCATEGORY));
	strncpy(wpcategory.name, x->name, 17);
}

 
/* --------------------------------------------------------------------------*/
/* 7.4.13  D150                                                              */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d150 (D150 *x)
{
	memset(&waypoint, 0, sizeof(WAYPOINT));
	waypoint.type = 150;
	strncpy(waypoint.ident, x->ident, sizeof(waypoint.ident)-1);
	waypoint.wpt_class = x->wpt_class;
	waypoint.posn = x->posn;
	strncpy(waypoint.cmnt, x->cmnt, sizeof(waypoint.cmnt)-1);

	if (x->wpt_class != D150_usr_wpt_class)
	{
	   waypoint.city = x->city;
	   strncpy(waypoint.state, x->state, 2);
	   waypoint.facility = x->name;
	   strncpy(waypoint.cc, x->cc, 2);
	}

	if (x->wpt_class == D150_apt_wpt_class)
	   waypoint.alt = x->alt;
}


/* --------------------------------------------------------------------------*/
/* 7.4.14  D151                                                              */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d151 (D151 *x)
{
	memset(&waypoint, 0, sizeof(WAYPOINT));
	waypoint.type = 151;
	strncpy(waypoint.ident, x->ident, sizeof(waypoint.ident)-1);
	waypoint.wpt_class = x->wpt_class;
	waypoint.posn = x->posn;
	strncpy(waypoint.cmnt, x->cmnt, sizeof(waypoint.cmnt)-1);
	waypoint.dst = x->dst;

	if (x->wpt_class != D150_usr_wpt_class)
	{
	   waypoint.city = x->city;
	   strncpy(waypoint.state, x->state, 2);
	   waypoint.facility = x->name;
	   strncpy(waypoint.cc, x->cc, 2);
	}

	if (x->wpt_class == D150_apt_wpt_class)
	   waypoint.alt = x->alt;
}


/* --------------------------------------------------------------------------*/
/* 7.4.15  D152                                                              */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d152 (D152 *x)
{
	memset(&waypoint, 0, sizeof(WAYPOINT));
	waypoint.type = 152;
	strncpy(waypoint.ident, x->ident, sizeof(waypoint.ident)-1);
	waypoint.wpt_class = x->wpt_class;
	waypoint.posn = x->posn;
	strncpy(waypoint.cmnt, x->cmnt, sizeof(waypoint.cmnt)-1);
	waypoint.dst = x->dst;

	if (x->wpt_class != D152_usr_wpt_class)
	{
	   waypoint.city = x->city;
	   strncpy(waypoint.state, x->state, 2);
	   waypoint.facility = x->name;
	   strncpy(waypoint.cc, x->cc, 2);
	}

	if (x->wpt_class == D152_apt_wpt_class)
	   waypoint.alt = x->alt;
}


/* --------------------------------------------------------------------------*/
/* 7.4.16  D154                                                              */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d154 (D154 *x)
{
	memset(&waypoint, 0, sizeof(WAYPOINT));
	waypoint.type = 154;
	strncpy(waypoint.ident, x->ident, sizeof(waypoint.ident)-1);
	waypoint.wpt_class = x->wpt_class;
	waypoint.posn = x->posn;
	strncpy(waypoint.cmnt, x->cmnt, sizeof(waypoint.cmnt)-1);
	waypoint.dst = x->dst;

	if (x->wpt_class != D154_usr_wpt_class)
	{
	   waypoint.city = x->city;
	   strncpy(waypoint.state, x->state, 2);
	   waypoint.facility = x->name;
	   strncpy(waypoint.cc, x->cc, 2);
	}

	if (x->wpt_class == D154_apt_wpt_class)
	   waypoint.alt = x->alt;

	waypoint.smbl = x->smbl;
}


/* --------------------------------------------------------------------------*/
/* 7.4.17  D155                                                              */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d155 (D155 *x)
{
	memset(&waypoint, 0, sizeof(WAYPOINT));
	waypoint.type = 155;
	strncpy(waypoint.ident, x->ident, sizeof(waypoint.ident)-1);
	waypoint.wpt_class = x->wpt_class;
	waypoint.posn = x->posn;
	strncpy(waypoint.cmnt, x->cmnt, sizeof(waypoint.cmnt)-1);
	waypoint.dst = x->dst;

	if (x->wpt_class != D155_usr_wpt_class)
	{
	   waypoint.city = x->city;
	   strncpy(waypoint.state, x->state, 2);
	   waypoint.facility = x->name;
	   strncpy(waypoint.cc, x->cc, 2);
	}

	if (x->wpt_class == D155_apt_wpt_class)
	   waypoint.alt = x->alt;

	waypoint.smbl = x->smbl;
	waypoint.dspl = x->dspl;
}


/* --------------------------------------------------------------------------*/
/* 7.4.18  D200                                                              */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d200 (D200 *x)
{
	route_header = *x;
}


/* --------------------------------------------------------------------------*/
/* 7.4.19  D201                                                              */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d201 (D201 *x)
{
	memset(&route, 0, sizeof(ROUTE));
	route.type = 201;
	route.nmbr = x->nmbr;
	strncpy(route.cmnt, x->cmnt, 20);
}


/* --------------------------------------------------------------------------*/
/* 7.4.20  D202                                                              */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d202 (D202 *x)
{
	memset(&route, 0, sizeof(ROUTE));
	route.type = 202;
	route.rte_ident = x->rte_ident;
}


/* --------------------------------------------------------------------------*/
/* 7.4.21  D210                                                              */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d210 (D210 *x)
{
	memset(&route_link, 0, sizeof(ROUTE_LINK));
	route_link.type = 210;
	route_link.klasse = x->klasse;
	route_link.ident = x->ident;
	strncpy((char *)route_link.subclass, (char *)x->subclass, 18);
}


/* --------------------------------------------------------------------------*/
/* 7.4.22  D300                                                              */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d300 (D300 *p)
{
	memset(&point, 0, sizeof(POINT));
	point.type = 300;
	point.time = p->time;
	point.posn = p->posn;
	point.new_trk = p->new_trk;
	addPoint();
}


/* --------------------------------------------------------------------------*/
/* 7.4.23  D301                                                              */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d301 (D301 *p)
{
	memset(&point, 0, sizeof(POINT));
	point.type = 301;
	point.time = p->time;
	point.posn = p->posn;
	point.new_trk = p->new_trk;
	point.alt = p->alt;
	point.dpth = p->dpth;
	addPoint();
}


/* --------------------------------------------------------------------------*/
/* 7.4.24  D302                                                              */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d302 (D302 *p)
{
	memset(&point, 0, sizeof(POINT));
	point.type = 302;
	point.time = p->time;
	point.posn = p->posn;
	point.new_trk = p->new_trk;
	point.alt = p->alt;
	point.dpth = p->dpth;
	point.temp = p->temp;
	addPoint();
}


/* --------------------------------------------------------------------------*/
/* 7.4.25  D303                                                              */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d303 (D303 *p)
{
	memset(&point, 0, sizeof(POINT));
	point.type = 303;
	point.time = p->time;
	point.posn = p->posn;
	point.alt = p->alt;
	point.heart_rate = p->heart_rate;
	addPoint();
}


/* --------------------------------------------------------------------------*/
/* 7.4.26  D304                                                              */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d304 (D304 *p)
{
	memset(&point, 0, sizeof(POINT));
	point.type = 304;
	point.time = p->time;
	point.posn = p->posn;
	point.alt = p->alt;
	point.heart_rate = p->heart_rate;
	point.distance = p->distance;
	point.cadence = p->cadence;
	point.sensor = p->sensor;
	addPoint();
}


/* --------------------------------------------------------------------------*/
/* 7.4.27  D310                                                              */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d310 (D310 *x)
{
	memset(&track, 0, sizeof(TRACK));
	track.type = 310;
	track.trk_ident = x->trk_ident;
	track.color = x->color;
	track.dspl = x->dspl;
}


/* --------------------------------------------------------------------------*/
/* 7.4.28  D311                                                              */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d311 (D311 *h)
{
	memset(&track, 0, sizeof(TRACK));
	track.type = 311;
	track.index = h->index;
}


/* --------------------------------------------------------------------------*/
/* 7.4.29  D312                                                              */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d312 (D312 *h)
{
	memset(&track, 0, sizeof(TRACK));
	track.type = 312;
	track.trk_ident = h->trk_ident;
	track.color = h->color;
	track.dspl = h->dspl;
}


/* --------------------------------------------------------------------------*/
/* 7.4.30  D400                                                              */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d400 (D400 *x)
{
	garmin_print_d400((D400 *)&x->wpt);
	waypoint.type = 400;
	waypoint.dst = x->dst;
}


/* --------------------------------------------------------------------------*/
/* 7.4.31  D403                                                              */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d403 (D403 *x)
{
	garmin_print_d103(&x->wpt);
	waypoint.type = 403;
	waypoint.dst = x->dst;
}


/* --------------------------------------------------------------------------*/
/* 7.4.32  D450                                                              */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d450 (D450 *x)
{
	garmin_print_d150(&x->wpt);
	waypoint.type = 450;
	waypoint.dst = x->dst;
	waypoint.idx = x->idx;
}


/* --------------------------------------------------------------------------*/
/* 7.4.33  D500                                                              */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d500 (D500 *x)
{
	memset(&almanac, 0, sizeof(ALMANAC));
	almanac.type = 500;
	almanac.wn = x->wn;
	almanac.toa = x->toa;
	almanac.af0 = x->af0;
	almanac.af1 = x->af1;
	almanac.e = x->e;
	almanac.sqrta = x->sqrta;
	almanac.m0 = x->m0;
	almanac.w = x->w;
	almanac.omg0 = x->omg0;
	almanac.odot = x->odot;
	almanac.i = x->i;
}


/* --------------------------------------------------------------------------*/
/* 7.4.34  D501                                                              */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d501 (D501 *x)
{
	memset(&almanac, 0, sizeof(ALMANAC));
	almanac.type = 501;
	almanac.wn = x->wn;
	almanac.toa = x->toa;
	almanac.af0 = x->af0;
	almanac.af1 = x->af1;
	almanac.e = x->e;
	almanac.sqrta = x->sqrta;
	almanac.m0 = x->m0;
	almanac.w = x->w;
	almanac.omg0 = x->omg0;
	almanac.odot = x->odot;
	almanac.i = x->i;
	almanac.hlth = x->hlth;
}


/* --------------------------------------------------------------------------*/
/* 7.4.35  D550                                                              */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d550 (D550 *x)
{
	memset(&almanac, 0, sizeof(ALMANAC));
	almanac.type = 550;
	almanac.wn = x->wn;
	almanac.toa = x->toa;
	almanac.af0 = x->af0;
	almanac.af1 = x->af1;
	almanac.e = x->e;
	almanac.sqrta = x->sqrta;
	almanac.m0 = x->m0;
	almanac.w = x->w;
	almanac.omg0 = x->omg0;
	almanac.odot = x->odot;
	almanac.i = x->i;
	almanac.svid = x->svid;
}


/* --------------------------------------------------------------------------*/
/* 7.4.36  D551                                                              */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d551 (D551 *x)
{
	memset(&almanac, 0, sizeof(ALMANAC));
	almanac.type = 551;
	almanac.wn = x->wn;
	almanac.toa = x->toa;
	almanac.af0 = x->af0;
	almanac.af1 = x->af1;
	almanac.e = x->e;
	almanac.sqrta = x->sqrta;
	almanac.m0 = x->m0;
	almanac.w = x->w;
	almanac.omg0 = x->omg0;
	almanac.odot = x->odot;
	almanac.i = x->i;
	almanac.svid = x->svid;
	almanac.hlth = x->hlth;
}


/* --------------------------------------------------------------------------*/
/* 7.4.37  D600                                                              */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d600 (D600 *x)
{
	datetime.year = x->year;
	datetime.month = x->month;
	datetime.day = x->day;
	datetime.hour = x->hour;
	datetime.minute = x->minute;
	datetime.second = x->second;
}


/* --------------------------------------------------------------------------*/
/* 7.4.38  D650                                                              */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d650 (D650 *x)
{
	memset(&flightbook, 0, sizeof(FLIGHTBOOK));
	flightbook.type = 650;
	flightbook.takeoff_time = x->takeoff_time;
	flightbook.landing_time = x->landing_time;
	flightbook.takeoff_posn = x->takeoff_posn;
	flightbook.landing_posn = x->landing_posn;
	flightbook.night_time = x->night_time;
	flightbook.num_landings = x->num_landings;
	flightbook.max_speed = x->max_speed;
	flightbook.max_alt = x->max_alt;
	flightbook.distance = x->distance;
	flightbook.cross_country_flag = x->cross_country_flag;
	flightbook.departure_name = x->departure_name;
	flightbook.departure_ident = x->departure_ident;
	flightbook.arrival_name = x->arrival_name;
	flightbook.arrival_ident = x->arrival_ident;
	flightbook.ac_id = x->ac_id;
}


/* ------------------------------------------------------------------------- */
/* 7.4.39  D700                                                              */
/* ------------------------------------------------------------------------- */

void disassemble::garmin_print_d700 (D700 *x)
{
	rpt.lat = x->lat;
	rpt.lon = x->lon;
}


/* --------------------------------------------------------------------------*/
/* 7.4.40  D800                                                              */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d800 (D800 *x)
{
	memset(&pvt, 0, sizeof(PVT));
	pvt.alt = x->alt;
	pvt.epe = x->epe;
	pvt.eph = x->eph;
	pvt.epv = x->epv;
	pvt.fix = x->fix;
	pvt.posn.lat = x->posn.lat;
	pvt.posn.lon = x->posn.lon;
	pvt.east = x->east;
	pvt.north = x->north;
	pvt.up = x->up;
	pvt.msl_hght = x->msl_hght;
	pvt.leap_scnds = x->leap_scnds;
	pvt.wn_days = x->wn_days;
	pvt.tow = x->tow;
}


/* --------------------------------------------------------------------------*/
/* 7.4.41  D906                                                              */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d906 (D906 *x)
{
	memset (&lap, 0, sizeof(LAP));
	lap.type = 906;
	lap.start_time = x->start_time;
	lap.total_time = x->total_time;
	lap.total_distance = x->total_distance;
	lap.begin.lat = x->begin.lat;
	lap.begin.lon = x->begin.lon;
	lap.end.lat = x->end.lat;
	lap.end.lon = x->end.lon;
	lap.calories = x->calories;
	lap.track_index = x->track_index;
	addLap();
}


/* --------------------------------------------------------------------------*/
/* 7.4.42  D1000                                                             */
/* --------------------------------------------------------------------------*/


void disassemble::garmin_print_d1000 (D1000 *x)
{
	memset(&run, 0, sizeof(RUN));
	garmin_print_d1002((D1002 *)&x->workout);
	run.type = 1000;
	run.track_index = x->track_index;
	run.sport_type = x->sport_type;
	run.first_lap_index = x->first_lap_index;
	run.last_lap_index = x->last_lap_index;
	run.program_type = x->program_type;
	run.virtual_partner.time = x->virtual_partner.time;
	run.virtual_partner.distance = x->virtual_partner.distance;
	addRun();
}


/* --------------------------------------------------------------------------*/
/* 7.4.43  D1001                                                             */
/* --------------------------------------------------------------------------*/


void disassemble::garmin_print_d1001 (D1001 *x)
{
	memset(&lap, 0, sizeof(LAP));
	lap.type = 1001;
	lap.start_time = x->start_time;
	lap.total_time = x->total_time;
	lap.total_distance = x->total_dist;
	lap.begin.lat = x->begin.lat;
	lap.begin.lon = x->begin.lon;
	lap.end.lat = x->end.lat;
	lap.end.lon = x->end.lon;
	lap.calories = x->calories;
	lap.index = x->index;
	lap.max_speed = x->max_speed;
	lap.avg_heart_rate = x->avg_heart_rate;
	lap.max_heart_rate = x->max_heart_rate;
	lap.intensity = x->intensity;
	addLap();
}


/* --------------------------------------------------------------------------*/
/* 7.4.44  D1002                                                             */
/* --------------------------------------------------------------------------*/


void disassemble::garmin_print_d1002 (D1002 *x)
{
unsigned int i;

	memset (&workout, 0, sizeof(WORKOUT));
	workout.type = 1002;
	strncpy (workout.name, x->name, 16);
	workout.num_valid_steps = x->num_valid_steps;

	if (x->num_valid_steps > 0)
	{
	   for (i = 0; i < x->num_valid_steps; i++)
	   {
	      if (i >= 20)
		 break;

	      strncpy (workout.steps[i].custom_name, x->steps[i].custom_name, 16);
	      workout.steps[i].intensity = x->steps[i].intensity;
	      workout.steps[i].duration_type = x->steps[i].duration_type;
	      workout.steps[i].duration_value = x->steps[i].duration_value;
	      workout.steps[i].target_type = x->steps[i].target_type;
	      workout.steps[i].target_value = x->steps[i].target_value;
	      workout.steps[i].target_custom_zone_low = x->steps[i].target_custom_zone_low;
	      workout.steps[i].target_custom_zone_high = x->steps[i].target_custom_zone_high;
	   }
	}
}


/* --------------------------------------------------------------------------*/
/* 7.4.45  D1003                                                             */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d1003 (D1003 *x)
{
	memset (&workout, 0, sizeof(WORKOUT));
	workout.type = 1003;
	strncpy (workout.workout_name, x->workout_name, 16);
	workout.day = x->day;
}


/* --------------------------------------------------------------------------*/
/* 7.4.46  D1004                                                             */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d1004 (D1004 *d)
{
int i;
int j;

	memset (&fitness, 0, sizeof(FITNESS));
	fitness.type = 1004;
	fitness.weight = d->weight;
	fitness.birth_year = d->birth_year;
	fitness.birth_month = d->birth_month;
	fitness.birth_day = d->birth_day;
	fitness.gender = d->gender;

	for (i = 0; i < 3; i++)
	{
	   fitness.activities[i].gear_weight = d->activities[i].gear_weight;
	   fitness.activities[i].max_heart_rate = d->activities[i].max_heart_rate;

	   for (j = 0; j < 5; j++)
	   {
	      fitness.activities[i].heart_rate_zones[j].low_heart_rate = d->activities[i].heart_rate_zones[j].low_heart_rate;
	      fitness.activities[i].heart_rate_zones[j].high_heart_rate = d->activities[i].heart_rate_zones[j].high_heart_rate;
	   }

	   for (j = 0; j < 10; j++)
	   {
	      fitness.activities[i].speed_zones[j].low_speed = d->activities[i].speed_zones[j].low_speed;
	      fitness.activities[i].speed_zones[j].high_speed = d->activities[i].speed_zones[j].high_speed;
	      strncpy (fitness.activities[i].speed_zones[j].name, d->activities[i].speed_zones[j].name, 16);
	   }
	}
}


/* --------------------------------------------------------------------------*/
/* 7.4.47  D1005                                                             */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d1005 (D1005 *limits)
{
	memset (&workout, 0, sizeof(WORKOUT));
	workout.type = 1005;
	workout.max_workouts = limits->max_workouts;
	workout.max_unscheduled_workouts = limits->max_unscheduled_workouts;
	workout.max_occurrences = limits->max_occurrences;
}


/* --------------------------------------------------------------------------*/
/* 7.4.48  D1006                                                             */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d1006 (D1006 *x)
{
	memset (&course, 0, sizeof(COURSE));
	course.type = 1006;
	course.index = x->index;
	strncpy(course.course_name, x->course_name, 16);
	course.track_index = x->track_index;
}


/* --------------------------------------------------------------------------*/
/* 7.4.49  D1007                                                             */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d1007 (D1007 *x)
{
	memset (&course, 0, sizeof(COURSE));
	course.type = 1007;
	course.course_index = x->course_index;
	course.lap_index = x->lap_index;
	course.total_time = x->total_time;
	course.total_dist = x->total_dist;
	course.begin.lat = x->begin.lat;
	course.begin.lon = x->begin.lon;
	course.end.lat = x->end.lat;
	course.end.lon = x->end.lon;
	course.avg_heart_rate = x->avg_heart_rate;
	course.max_heart_rate = x->max_heart_rate;
	course.avg_cadence = x->avg_cadence;
	course.intensity = x->intensity;
}


/* --------------------------------------------------------------------------*/
/* 7.4.50  D1008                                                             */
/* --------------------------------------------------------------------------*/


void disassemble::garmin_print_d1008 (D1008 *w)
{
	/* For some reason, D1008 is identical to D1002. */
	garmin_print_d1002((D1002 *)w);
	workout.type = 1008;
}


/* --------------------------------------------------------------------------*/
/* 7.4.51  D1009                                                             */
/* --------------------------------------------------------------------------*/


void disassemble::garmin_print_d1009 (D1009 *x)
{
	memset(&run, 0, sizeof(RUN));
	garmin_print_d1002((D1002 *)&x->workout);
	memmove (&run.workout, &workout, sizeof (WORKOUT));
	run.type = 1009;
	run.track_index = x->track_index;
	run.sport_type = x->sport_type;
	run.first_lap_index = x->first_lap_index;
	run.last_lap_index = x->last_lap_index;
	run.program_type = x->program_type;
	run.virtual_partner.time = x->quick_workout.time;
	run.virtual_partner.distance = x->quick_workout.distance;
	run.multisport = x->multisport;
	addRun();
}


/* --------------------------------------------------------------------------*/
/* 7.4.52  D1010                                                             */
/* --------------------------------------------------------------------------*/


void disassemble::garmin_print_d1010 (D1010 *x)
{
	memset(&run, 0, sizeof(RUN));
	garmin_print_d1002((D1002 *)&x->workout);
	run.type = 1010;
	run.track_index = x->track_index;
	run.sport_type = x->sport_type;
	run.first_lap_index = x->first_lap_index;
	run.last_lap_index = x->last_lap_index;
	run.program_type = x->program_type;
	run.virtual_partner.time = x->virtual_partner.time;
	run.virtual_partner.distance = x->virtual_partner.distance;
	run.multisport = x->multisport;
	addRun();
}


/* --------------------------------------------------------------------------*/
/* 7.4.53  D1011                                                             */
/* --------------------------------------------------------------------------*/


void disassemble::garmin_print_d1011 (D1011 *x)
{
	memset(&lap, 0, sizeof(LAP));
	lap.type = 1011;
	lap.start_time = x->start_time;
	lap.total_time = x->total_time;
	lap.total_distance = x->total_dist;
	lap.begin.lat = x->begin.lat;
	lap.begin.lon = x->begin.lon;
	lap.end.lat = x->end.lat;
	lap.end.lon = x->end.lon;
	lap.calories = x->calories;
	lap.index = x->index;
	lap.max_speed = x->max_speed;
	lap.avg_heart_rate = x->avg_heart_rate;
	lap.max_heart_rate = x->max_heart_rate;
	lap.intensity = x->intensity;
	lap.avg_cadence = x->avg_cadence;
	lap.trigger_method = x->trigger_method;
	addLap();
}


/* --------------------------------------------------------------------------*/
/* 7.4.54  D1012                                                             */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d1012 (D1012 *x)
{
	memset (&course, 0, sizeof(COURSE));
	course.type = 1012;
	course.course_index = x->course_index;
	strncpy (course.course_name, x->name, 11);
	course.track_point_time = x->track_point_time;
	course.point_type = x->point_type;
}


/* --------------------------------------------------------------------------*/
/* 7.4.55  D1013                                                             */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d1013 (D1013 *x)
{
	memset (&course, 0, sizeof(COURSE));
	course.type = 1012;
	course.max_courses = x->max_courses;
	course.max_course_laps = x->max_course_laps;
	course.max_course_pnt = x->max_course_pnt;
	course.max_course_trk_pnt = x->max_course_trk_pnt;
}


/* --------------------------------------------------------------------------*/
/* 7.4.XX  D1015 (Undocumented)                                              */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d1015 (D1015 *x)
{
	memset(&lap, 0, sizeof(LAP));
	lap.type = 1011;
	lap.start_time = x->start_time;
	lap.total_time = x->total_time;
	lap.total_distance = x->total_dist;
	lap.begin.lat = x->begin.lat;
	lap.begin.lon = x->begin.lon;
	lap.end.lat = x->end.lat;
	lap.end.lon = x->end.lon;
	lap.calories = x->calories;
	lap.index = x->index;
	lap.max_speed = x->max_speed;
	lap.avg_heart_rate = x->avg_heart_rate;
	lap.max_heart_rate = x->max_heart_rate;
	lap.intensity = x->intensity;
	lap.avg_cadence = x->avg_cadence;
	lap.trigger_method = x->trigger_method;
	addLap();
}


/* ========================================================================= */
/* garmin_print_data                                                         */
/* ========================================================================= */

void disassemble::garmin_print_data (garmin_data *d)
{
	if (!d)
	   return;

#define CASE_PRINT(x) \
  case data_D##x: garmin_print_d##x((D##x *)d->data); break

	switch (d->type)
	{
	   case data_Dlist:
	      garmin_print_dlist ((garmin_list *)d->data);
	   break;

	   CASE_PRINT(100);
	   CASE_PRINT(101);
	   CASE_PRINT(102);
	   CASE_PRINT(103);
	   CASE_PRINT(104);
	   CASE_PRINT(105);
	   CASE_PRINT(106);
	   CASE_PRINT(107);
	   CASE_PRINT(108);
	   CASE_PRINT(109);
	   CASE_PRINT(110);
	   CASE_PRINT(120);
	   CASE_PRINT(150);
	   CASE_PRINT(151);
	   CASE_PRINT(152);
	   CASE_PRINT(154);
	   CASE_PRINT(155);
	   CASE_PRINT(200);
	   CASE_PRINT(201);
	   CASE_PRINT(202);
	   CASE_PRINT(210);
	   CASE_PRINT(300);
	   CASE_PRINT(301);
	   CASE_PRINT(302);
	   CASE_PRINT(303);
	   CASE_PRINT(304);
	   CASE_PRINT(310);
	   CASE_PRINT(311);
	   CASE_PRINT(312);
	   CASE_PRINT(400);
	   CASE_PRINT(403);
	   CASE_PRINT(450);
	   CASE_PRINT(500);
	   CASE_PRINT(501);
	   CASE_PRINT(550);
	   CASE_PRINT(551);
	   CASE_PRINT(600);
	   CASE_PRINT(650);
	   CASE_PRINT(700);
	   CASE_PRINT(800);
	   CASE_PRINT(906);
	   CASE_PRINT(1000);
	   CASE_PRINT(1001);
	   CASE_PRINT(1002);
	   CASE_PRINT(1003);
	   CASE_PRINT(1004);
	   CASE_PRINT(1005);
	   CASE_PRINT(1006);
	   CASE_PRINT(1007);
	   CASE_PRINT(1008);
	   CASE_PRINT(1009);
	   CASE_PRINT(1010);
	   CASE_PRINT(1011);
	   CASE_PRINT(1012);
	   CASE_PRINT(1013);
	   CASE_PRINT(1015);
	   default: break;
	}

#undef CASE_PRINT
}

/*
 * The following functions are to calculate some GPS related parameters.
 * Base is the WGS84 date.
 *
 * This functions are not needed tho handle the files and data out of
 * the GPS-device!
 */
double disassemble::CalcRad(double lat)
/* earth's radius of curvature in meters at specified latitude.*/
{
const double a = 6378.137;
const double e2 = 0.081082 * 0.081082;

	/*
	 * the radius of curvature of an ellipsoidal Earth in the plane of a
	 * meridian of latitude is given by
	 *
	 * R' = a * (1 - e^2) / (1 - e^2 * (sin(lat))^2)^(3/2)
	 *
	 * where a is the equatorial radius,
	 * b is the polar radius, and
	 * e is the eccentricity of the ellipsoid = sqrt(1 - b^2/a^2)
	 *
	 * a = 6378 km (3963 mi) Equatorial radius (surface to center distance)
	 * b = 6356.752 km (3950 mi) Polar radius (surface to center distance)
	 * e = 0.081082 Eccentricity
	 */
	double sc = sin(Deg2Rad(lat));
	double x = a * (1.0 - e2);
	double z = 1.0 - e2 * sc * sc;
	double y = pow(z, 1.5);
	double r = x / y;

	return r * 1000.0; // Convert to meters
}

double disassemble::earth_distance(double lat1, double lon1, double lat2, double lon2)
/* distance in meters between two points specified in degrees. */
{
double x1 = CalcRad(lat1) * cos(Deg2Rad(lon1)) * sin(Deg2Rad(90-lat1));
double x2 = CalcRad(lat2) * cos(Deg2Rad(lon2)) * sin(Deg2Rad(90-lat2));
double y1 = CalcRad(lat1) * sin(Deg2Rad(lon1)) * sin(Deg2Rad(90-lat1));
double y2 = CalcRad(lat2) * sin(Deg2Rad(lon2)) * sin(Deg2Rad(90-lat2));
double z1 = CalcRad(lat1) * cos(Deg2Rad(90-lat1));
double z2 = CalcRad(lat2) * cos(Deg2Rad(90-lat2));
double a = (x1*x2 + y1*y2 + z1*z2)/pow(CalcRad((lat1+lat2)/2),2);

	// a should be in [1, -1] but can sometimes fall outside it by
	// a very small amount due to rounding errors in the preceding
	// calculations (this is prone to happen when the argument points
	// are very close together). Thus we constrain it here.
	if (abs(a) > 1)
	   a = 1;
	else if (a < -1)
	   a = -1;

	return CalcRad((lat1+lat2) / 2) * acos(a);
}
